"""The application's model objects"""
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import relation,backref
from sqlalchemy.ext.declarative import declarative_base as base
Base=base()
from blog.model import meta
import hashlib
import logging
log=logging.getLogger('Model')

def init_model(engine):
    """Call me before using any of the tables or classes in the model"""
    ## Reflected tables must be defined and mapped here
    #global reflected_table
    #reflected_table = sa.Table("Reflected", meta.metadata, autoload=True,
    #                           autoload_with=engine)
    #orm.mapper(Reflected, reflected_table)
    #
    meta.Session.configure(bind=engine)
    meta.engine = engine


Password_table=sa.Table('password',meta.metadata,
                            sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                            sa.Column('pwdmd5',sa.types.Text),
                            sa.Column('pwdsha1',sa.types.Text),
                            sa.Column('pwdsha224',sa.types.Text),
                            sa.Column('pwdsha256',sa.types.Text),
                            sa.Column('pwdsha384',sa.types.Text),
                            sa.Column('pwdsha512',sa.types.Text),
                        )

Profile_table=sa.Table('profile',meta.metadata,
                        sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                        sa.Column('sign',sa.types.UnicodeText),
                        sa.Column('description',sa.types.UnicodeText),
                        sa.Column('aka',sa.types.Unicode(100)),
                    )

Right_table=sa.Table('right',meta.metadata,
                        sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                        sa.Column('name',sa.types.Text),
                        sa.Column('readright',sa.types.Integer),
                        sa.Column('writeright',sa.types.Integer),
                        sa.Column('replyright',sa.types.Integer),
                        sa.Column('manageright',sa.types.Integer),
                        sa.Column('createright',sa.types.Integer),
                        sa.Column('secrect',sa.types.Integer),
                    )

User_table=sa.Table('user',meta.metadata,
                        sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                        sa.Column('username',sa.types.Unicode(100)),
                        sa.Column('email',sa.types.String(400)),
                        sa.Column('hidden',sa.types.Boolean),
                        sa.Column('rid',sa.ForeignKey('right.id')),
                        sa.Column('pfid',sa.ForeignKey('profile.id')),
                        sa.Column('pid',sa.ForeignKey('password.id')),
                    )

Blogger_table=sa.Table('blogger',meta.metadata,
                            sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                            sa.Column('name',sa.types.Unicode(100)),
                            sa.Column('info',sa.types.UnicodeText),
                            sa.Column('summary',sa.types.Unicode(100)),
                            sa.Column('hidden',sa.types.Boolean),
                            sa.Column('rid',sa.ForeignKey('right.id')),
                        )

Thread_table=sa.Table('thread',meta.metadata,
                        sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                        sa.Column('hidden',sa.types.Boolean),
                        sa.Column('rid',sa.ForeignKey('right.id')),
                        sa.Column('uid',sa.ForeignKey('user.id')),
                      )

Article_table=sa.Table('article',meta.metadata,
                        sa.Column('id',sa.types.Integer,primary_key=True,autoincrement=True),
                        sa.Column('title',sa.types.UnicodeText),
                        sa.Column('content',sa.types.Unicode(100)),
                        sa.Column('hidden',sa.types.Boolean),
                        sa.Column('tid',sa.ForeignKey('thread.id')),
                        sa.Column('uid',sa.ForeignKey('user.id')),
                        sa.Column('rid',sa.ForeignKey('right.id')),
                        )

MidBlogger=sa.Table('midblogger',meta.metadata,
                    sa.Column('uid',sa.types.Integer,sa.ForeignKey('user.id')),
                    sa.Column('bid',sa.types.Integer,sa.ForeignKey('blogger.id')),
                    sa.Column('tid',sa.types.Integer,sa.ForeignKey('thread.id')),
                )

class Article(object):
    
    def __init__(self,user,title,content,hidden=False):
        self.user=user
        self.edit(title,content)
        self.hidden=hidden

    def edit(self,title=None,content=None,hidden=False):
        if title is not None : self.title=title
        if content is not None : self.content=content
        self.hidden=hidden

    def set_hidden(self,hidden=True):
        self.hidden=hidden

class Thread(object):

    def __init__(self,user,mainArticle,hidden=False):
        if not isinstance(mainArticle,Article):
            raise TypeError('reply must be an Article instance')
        self.articles=[mainArticle]
        self.users.extend(user if isinstance(user,list) else [user])
        self.hidden=hidden

    def add_reply(self,reply):
        if not isinstance(reply,Article):
            raise TypeError('reply must be an Article instance')
        self.articles.append(reply)
    
    def set_hidden(self,hidden=True):
        self.hidden=hidden

    def set_right(self,right):
        if not isinstance(right,Right):
            raise TypeError('reply must be an Right instance')
        self.right=right

class Blogger(object):
    
    def __init__(self,name,info=None,summary=None,hidden=False):
        self.name=name
        self.info=info if info else ''
        self.summary=summary if info else ''
        self.hidden=hidden
    
    def add_thread(self,thread):
        if not isinstance(thread,Thread):
            raise TypeError('thread must be a thread instance')
        self.threads.append(thread)

    def set_hidden(self,hidden=True):
        self.hidden=hidden

class Password(object):
    
    def __init__(self,pwd):
        self.pwdmd5=hashlib.md5(pwd).hexdigest()
        self.pwdsha1=hashlib.sha1(pwd).hexdigest()
        self.pwdsha224=hashlib.sha224(pwd).hexdigest()
        self.pwdsha256=hashlib.sha256(pwd).hexdigest()
        self.pwdsha384=hashlib.sha384(pwd).hexdigest()
        self.pwdsha512=hashlib.sha512(pwd).hexdigest()

    def auth(self,pwd):
        try :
            assert self.pwdmd5==hashlib.md5(pwd).hexdigest()
            assert self.pwdsha1==hashlib.sha1(pwd).hexdigest()
            assert self.pwdsha224==hashlib.sha224(pwd).hexdigest()
            assert self.pwdsha256==hashlib.sha256(pwd).hexdigest()
            assert self.pwdsha384==hashlib.sha384(pwd).hexdigest()
            assert self.pwdsha512==hashlib.sha512(pwd).hexdigest()
        except AssertionError:
            return False
        else :
            return True

class Profile(object):

    def __init__(self,sign=u'',description=u'',aka=u''):
        self.sign=sign
        self.description=description
        self.aka=aka

class Right(object):
    
    def __init__(self,name,read=10,write=10,reply=10,manage=0,create=5,secrect=0):
        self.name=name
        self.readright=read
        self.writeright=write
        self.replyright=reply
        self.manageright=manage
        self.createright=create
        self.secrect=secrect

class User(object):
    

    def __init__(self,username,email):
        self.username=username
        self.email=email

    def set_password(self,password):
        self.password=Password(password)

    def set_profile(self,profile):
        if not isinstance(profile,Profile):
            raise TypeError('profile must be a Profile instance')
        self.profile=profile

    def set_right(self,right):
        if not isinstance(right,Right):
            raise TypeError('right must be a Right instance')
        self.right=right

    def add_blogger(self,blogger):
        if not isinstance(blogger,Blogger):
            raise TypeError('blogger must be a Blogger instance')
        self.bloggers.append(blogger)

    def __unicode__(self):
        return unicode(self.username)

    def __str__(self):
        return self.username

    __repr__=__str__

orm.mapper(Right,Right_table)
orm.mapper(Profile,Profile_table)
orm.mapper(Password,Password_table)
orm.mapper(User,User_table,properties={
            'password' : relation(Password,backref=backref('user',uselist=False)),
            'profile' : relation(Profile,backref=backref('user',uselist=False)),
            'right' : relation(Right,uselist=False),
        })

orm.mapper(Article,Article_table,properties={
            'user' : relation(User,uselist=False,backref='articles'),
            'right' : relation(Right,uselist=False),
            })
orm.mapper(Thread,Thread_table,properties={
            'users' : relation(User,secondary=MidBlogger,backref='threads'),
            'articles' : relation(Article,backref=backref('thread',uselist=False)),
            'right' : relation(Right,uselist=False),
        })

orm.mapper(Blogger,Blogger_table,properties={
            'users' : relation(User,secondary=MidBlogger,backref='bloggers'),
            'threads' : relation(Thread,secondary=MidBlogger,backref='bloggers'),
            'right' : relation(Right,uselist=False),
        })
